(function(){
   angular.module('app').controller("noteController", ['$scope', '$sce', 'NoteBook', 'Note', '$dialog', 'localStorageService', 'urlBase', 'host', 'debounce', 'MessageBox', '$http',
           function($scope, $sce, NoteBook, Note, $dialog, localStorageService, urlBase, host, debounce, MessageBox, $http) {
           NoteBook.query({}, function success(data) {
               $scope.notebooks = data;
               init();
           });

           //初始化所选的笔记，如果到不到的话，自动选第一个
           function init() {
               var prevSelectedBook = localStorageService.get("selectedBook"),
                   prevSelectedNote = localStorageService.get("selectedNote"),
                   found = false,
                   book = null;

               if ($scope.notebooks) {
                   if (prevSelectedBook) {
                       for (var i = 0; book = $scope.notebooks[i]; i++ ) {
                           if (book.id == prevSelectedBook.id) {
                               found = true;
                               break;
                           }
                       }
                   }

                   book = found ? book : $scope.notebooks[0];

                   $scope.selectNotebook(book);
                   $scope.queryNotesFromNoteBookId(book.id, {
                       success: function(){
                           var note = null;
                           if (prevSelectedNote && $scope.notes && $scope.notes.length) {
                               note = $scope.notes.filter(function(note){
                                   return note.id == prevSelectedNote.id;
                               })[0];
                           }
                           $scope.selectNote(note ? note : $scope.notes[0]);
                       }
                   });
               }

               //init accordion status
               ["isShortcutOpen", "isNotebookOpen", "isTagOpen"].forEach(function(status){
                   $scope[status] = (localStorageService.get(status) + '') != "false"; //get会返回字符串，为了让以后阅读更确定这是字符串，故+''
               });

               setTimeout(syncDatabase(), 1000);
           }

           function syncDatabase() {
               $http({
                   method: "POST",
                   url: host + "rest/note/35"/*
                   data: $.param({
                       email: email,
                       password: password
                   }),
                   headers: {'Content-Type': 'application/x-www-form-urlencoded'}*/
               }).success(function(){

                   });
           }

           $scope.$watch("selectedBook", function(v){
               if (!v || !v.id) return;//加上判断的原因是，init()函数还没还得及调，这边就已经赋上值了
               localStorageService.add("selectedBook",  v);
           });

           $scope.$watch("selectedNote", function(v){
               if (!v || !v.id) {
                   if ($scope.markdownEditor) {
                       $scope.markdownEditor.setReadOnly(true);
                   }
                   return;
               }
               $scope.markdownEditor.setReadOnly(false);
               localStorageService.add("selectedNote", v);
           });

           ["isShortcutOpen", "isNotebookOpen", "isTagOpen"].forEach(function(status){
               $scope.$watch(status, function(v){
                   if (typeof v != "undefined") {
                       localStorageService.add(status, !!v);
                   }
               });
           });

           var sortMethods =  [
               {
                   name: "创建时间",
                   prop: "created_at"
               },
               {
                   name: '修改时间',
                   prop: "updated_at"
               },
               {
                   name: '标题(试验)',
                   prop: 'title_pinyin'
               }
           ];

           /**
            * if a > b, return 1.
            * if a < b, return -1
            * if a == b, return 0
            * @param a
            * @param b
            */
           function compare(a, b) {
               if (angular.isString(a) || angular.isString(b)) {
                   if (String.prototype.localeCompare) {
                       return (a+'').localeCompare(b);
                   }
               }

               if (a == b) return 0;
               return (a - b) > 0 ? 1 : -1;
           }

           function sortNotes() {
               var sm = $scope.sortMethod;
               var so = $scope.sortOrder;
               $scope.notes.sort(function(note1, note2){
                   var res = compare(note1[sm.prop], note2[sm.prop]);
                   return (so == 'asc') ? res : -res;
               });
           }

           //每30秒自动保存一次
           setInterval(function(){
               var cnote = $scope.selectedNote;
               cnote && $scope.saveNote(cnote);
               console.log('auto saving ' + cnote.title);
           }, 1000 * 30);

           angular.extend($scope, {
               aceThemes: [{name: "ambiance", path: "ace/theme/ambiance"},
                   {name: "chaos", path: "ace/theme/chaos"},
                   {name: "chrome", path: "ace/theme/chrome", selected: true},
                   {name: "clouds", path: "ace/theme/clouds"},
                   //{name: "clouds midnight", path: "ace/theme/clouds_midnight"},
                   {name: "cobalt", path: "ace/theme/cobalt"},
                   {name: "crimson editor", path: "ace/theme/crimson_editor"},
                   {name: "dawn", path: "ace/theme/dawn"},
                   {name: "dreamweaver", path: "ace/theme/dreamweaver"},
                   {name: "eclipse", path: "ace/theme/eclipse"},
                   {name: "github", path: "ace/theme/github"},
                   {name: "idle fingers", path: "ace/theme/idle_fingers"},
                   {name: "merbivore", path: "ace/theme/merbivore"},
                   {name: "merbivore soft", path: "ace/theme/merbivore_soft"},
                   {name: "mono industrial", path: "ace/theme/mono_industrial"},
                   {name: "monokai", path: "ace/theme/monokai"},
                   {name: "pastel on dark", path: "ace/theme/pastel_on_dark"},
                   {name: "solarized dark", path: "ace/theme/solarized_dark"},
                   {name: "solarized light", path: "ace/theme/solarized_light"},
                   {name: "terminal", path: "ace/theme/terminal"},
                   {name: "textmate", path: "ace/theme/textmate"},
                   {name: "tomorrow", path: "ace/theme/tomorrow"},
                   {name: "tomorrow night", path: "ace/theme/tomorrow_night"},
                   // {name: "tomorrow night blue", path: "ace/theme/tomorrow_night_blue"},
                   {name: "tomorrow night bright", path: "ace/theme/tomorrow_night_bright"},
                   {name: "tomorrow_night eighties", path: "ace/theme/tomorrow_night_eighties"},
                   {name: "twilight", path: "ace/theme/twilight"},
                   // {name: "vibrant ink", path: "ace/theme/vibrant_ink"},
                   {name: "xcode", path: "ace/theme/xcode"}],
               // nc means noteController
               // 在html中使用nc_set(name, value)即可很明确地知道调用的是noteController的scope的方法
               ncSet: function(name, value){
                   //console.log('setting [' + name +"]:" + value);
                   $scope[name] = value;
               },
               applyTheme: function(theme) {
                   try {
                       $scope.markdownEditor.setTheme(theme.path);
                       $scope.aceThemes.forEach(function(t){
                           t.selected = false;
                       });
                       theme.selected = true;
                   } catch(e){}
               },
               test: function(x) {
                 console.log(x);
               },
               searchText: '',
               searchType: 'all',
               searchScope: -1,
               outline: [],
               setSearchType: function(st){
                   $scope.searchType = st;
               },
               setSearchScope: function(ss){
                   $scope.searchScope = ss;
               },
               performSearch: function () {
                   Note.search({
                       text: $scope.searchText, /*要搜索的内容*/
                       scope: $scope.searchScope, /*{-1|Integer} 值为all或notebookId*/
                       type: $scope.searchType /*{'all'|'title'}*/
                   }, function (notes) {
                       $scope.notes = notes;
                   });
               },
               sortMethods: sortMethods,
               sortMethod: sortMethods[0],
               sortOrder: 'asc',
               applySortMethod: function (sm) {
                   $scope.sortMethod = sm;
                   sortNotes();
               },
               applySortOrder: function (so) {
                   $scope.sortOrder = so;
                   sortNotes();
               },
               applyURL: function (url) {
                   $scope.insertText("![altText](" + url + ")");
                   $scope.markdownEditor.$notify();
               },
               bShowEditBox: true,
               bShowPreviewBox: true,
               /**
                * @param show [boolean|optional], 如果传入了show, 则将对应值设为show的值，否则toggle之。
                */
               toggleEditBox: function(show){
                   $scope.bShowEditBox = arguments.length === 0 ? !$scope.bShowEditBox : show;
               },
               togglePreviewBox: function(show) {
                   $scope.bShowPreviewBox = arguments.length === 0 ?  !$scope.bShowPreviewBox : show;
               },
               notebooks: mockup.notebooks,
               tags: mockup.notetags,
               shortcuts: mockup.shortcuts,
               notes: mockup.notes,
               currentNote: null,
               selectedBook: null,
               selectedTag: null,
               selectNotebook: function selectNotebook (notebook) {
                   $scope.selectedBook = notebook;
               },
               selectTag: function selectTag (tag) {
                   $scope.selectedTag = tag;
               },
               selectShortcut: function selectShortcut(shortcut) {
                   $scope.selectedShortcut = shortcut;
               },
               selectNote: function selectNote(note) {
                   if (!note) return;
                   //首先，保存正在编辑的
                   if ($scope.selectedNote) {
                       $scope.saveNote($scope.selectedNote);
                   }

                   $scope.selectedNote = note;

                   function delayfinishLoading(){
                       setTimeout(function(){
                           //必须判断，因为回调后的状态不可预知
                           if ($scope.selectedNote == note) {
                               $scope.loadingNote = false;
                               $scope.$apply();
                           }
                       }, 50);
                   }
                   if (note.id) {
                       $scope.loadingNote = true;
                       note.$get(delayfinishLoading, delayfinishLoading);
                   }
               },
               createNote: function createNote(){
                   var note = new Note(),
                       nbId = $scope.selectedBook.id;
                   note.title = "新建笔记";
                   note.nbId = $scope.selectedBook.id;
                   $scope.loadingNoteList = true;
                   note.$save(function(){
                       if ($scope.selectedBook && $scope.selectedBook.id === nbId) {
                           $scope.notes.unshift(note);
                           $scope.loadingNoteList = false;

                           // shit! visiting dom node again!
                           setTimeout(function(){
                               var ndNote =  $(".note-index-" + note.id);
                               if (!ndNote.length) return;
                               ndNote.focus();
                               var range = document.createRange();
                               range.selectNodeContents(ndNote[0]);
                               var sel = window.getSelection();
                               sel.removeAllRanges();
                               sel.addRange(range);

                           });
                       }
                   }, function(){
                       $scope.loadingNoteList = false;
                   });
               },
               saveNote: function saveNote(note) {
                   if (!note.dirty) return;
                   $scope.savingNote = true;
                   //1. 因为服务器返回的Note是不带正文的，因此用一个tempNote做缓冲
                   //2. 不应该重设body值，这样会导致编辑器光标回到起点
                   var tempNote = new Note(note);
                   tempNote.$save(function(){
                       angular.extend(note, {
                           dirty: false,
                           updated_at: tempNote.updated_at, //更新lastModifiedDate
                           id: tempNote.id //对于新建的note,需要为其设上id
                       });
                       $scope.savingNote = false;
                   }, function(){
                       $scope.savingNote = false;
                   });

               },
               deleteNote: function deleteNote(note) {
                   note.$delete(function success(){
                       var index = $scope.notes.indexOf(note);
                       if (index !== -1) { //等于-1的情况可能是，当前用户已经切换了notebook
                           if ($scope.selectedNote == note) {
                               $scope.selectedNote = null;
                           }
                           $scope.notes.splice(index, 1);
                       }
                   }, function failure(){

                   });
               },
               dropNotebook: function (note, nbScope) {
                   var nbId = nbScope.notebook.id;
                   if (!nbId) return;
                   note.$set({
                       nb_id: nbScope.notebook.id
                   }, function(note){
                       if (note.nb_id !== $scope.selectedBook.id) {
                           note.detach($scope.notes);
                       }
                   });
               },
               notebookAllowDrop: function (item, nbScope) {
                   if (item.id && item.nb_id && item.nb_id !== nbScope.notebook.id) {
                       return true;
                   }
               },
               dragNote: function(note){
                   return note;
               },
               renameNotebook: function (notebook) {
                   var outScope = $scope;
                   $dialog.dialog({
                       backdrop: true,
                       keyboard: true,
                       backdropClick: true,
                       dialogClass:"modal auto-modal",
                       templateUrl: urlBase + "public/template/new-notebook.html", // OR: templateUrl: 'path/to/view.html',
                       controller: ['$scope', 'dialog', function ($scope, dialog) { //注：此处注入的dialog和$dialog是完全不同的
                           angular.extend($scope, {
                               title: '重命名笔记本',
                               name: notebook.name,
                               placeholder: '请输入新的笔记本名字',
                               save: function (name) {
                                   if (name !== notebook.name) {
                                       notebook.$set({
                                           name: name
                                       }, function(){
                                           dialog.close();
                                       });
                                   } else {
                                       dialog.close();
                                   }
                               },
                               close: function() {
                                   dialog.close();
                               }
                           });
                       }]
                   }).open();
               },
               deleteNotebook: function (notebook) {
                   MessageBox({
                       title: "删除笔记本",
                       message: "删除笔记本会导致其下的笔记全部丢失，确认删除?",
                       buttons:[{label: "取消", result: false}, {label: "确认", result: true, cssClass: "btn-primary"}],
                       dialogClass: 'modal auto-modal warning',
                       close: function(shouldDelete) {
                           if (!shouldDelete) return;
                           notebook.$delete(function(){
                               var index = $scope.notebooks.indexOf(notebook);
                               if (index !== -1) {
                                   if ($scope.selectedBook == notebook) {
                                       $scope.selectedBook = null;
                                   }
                                   $scope.notebooks.splice(index, 1);
                               }
                           });
                       }
                   }).open();
               },
               togglePreviewHandlerStyle: function togglePreviewHandlerStyle() {
                   var style = $scope.previewHandlerStyle,
                       show = !(style && style._flag);

                   $scope.previewHandlerStyle = show ? {
                       display: "flex",
                       _flag: 1
                   } : {
                       display: "a_invalid_value"
                   };
                   $scope.isPreviewHandlerShow = show;
               },
               insertText: function(text, position) {
                   var editor = $scope.markdownEditor;
                   position = position || editor.getCursorPosition();
                   editor.getSession().insert(position, text);
               },
               openPurePreview: function(){
                   $scope.purePreview = true;
               },
               queryNotesFromNoteBookId: function queryNotesFromNoteBookId(id, cb) {
                   var start = new Date();
                   $scope.loadingNoteList = true;
                   Note.query({
                       "nb_id": id
                   }, function(notes){//success
                       $scope.notes = notes;
                       sortNotes();
                       $scope.loadingNoteList = false;
                       cb && cb.success();
                       console.log((new Date()  - start)/1000);
                   }, function() {//fail
                       $scope.loadingNoteList = false;
                       cb && cb.fail();
                   });
               },
               resizeEditor: function() {
                   this.markdownEditor.resize(true);
               },
               markdown: (function(){
                   marked.setOptions({
                       gfm: true,
                       highlight: function (code, lang) {
                           var result = code,
                               lang = lang || "javascript";
                           try {
                               result = hljs.highlight(lang, code).value;//如果lang不在支持范围内，会报错
                           } catch (ex) {
                               result = hljs.highlightAuto(code).value;
                           }
                           return result;
                       },
                       tables: true,
                       breaks: false,
                       pedantic: false,
                       sanitize: false,
                       smartLists: true,
                       smartypants: false,
                       langPrefix: 'lang-'
                   });

                   // simple cache for performance reason.
                   var cacheKey = '';
                   var cacheValue = '';
                   var count = 0;

                   return function (input) {
                       if (cacheKey === input) {
                           return cacheValue;
                       }

                       cacheKey = input || "";

                       var tokens = marked.lexer(cacheKey);
                       var outline = $scope.outline = [];
                       angular.forEach(tokens, function(token) {
                           token.class = token.random + " mdSection";
                           if (token.type === "heading") {
                               token.id = "h" + (count++)%100000;
                               outline.push(token);
                           }
                       });
                       $scope.mdTokens = angular.copy(tokens);
                       cacheValue = $sce.trustAsHtml(marked.parser(tokens));

                       return cacheValue;
                   };
               }()),
               setTargetPlace: function(selector, offset) {
                   $scope.preview_target = selector;
                   $scope.preview_target_offset = offset || 0;
               },
               opencreateNoteBookDialog: function opencreateNoteBookDialog() {
                   var outScope = $scope;
                   $dialog.dialog({
                       backdrop: true,
                       keyboard: true,
                       backdropClick: true,
                       dialogClass:"modal auto-modal",
                       templateUrl: urlBase + "public/template/new-notebook.html", // OR: templateUrl: 'path/to/view.html',
                       controller: ['$scope', 'dialog', function ($scope, dialog) { //注：此处注入的dialog和$dialog是完全不同的
                           angular.extend($scope, {
                               title: '新建笔记本',
                               placeholder: '请输入新笔记本的名字',
                               save: function (name) {
                                   var nb = new NoteBook({
                                       name: name
                                   });
                                   nb.$save(function(){
                                       outScope.notebooks.push(nb);
                                       dialog.close();
                                   })
                               },
                               close: function() {
                                   dialog.close();
                               }
                           });
                       }]
                   }).open();
               },
               /**
                * 当用户滑动preview区域时，触发。
                * @param evt
                * @param elm
                */
               previewScroll: function(evt, elm) {
                   if (!$scope.mouse_on_preview) {
                       return;
                   }

                   var mdSectionNodese = elm.find(".mdSection"),
                       offsetTop = elm.offset().top,
                       offset,
                       top,
                       lastNode,
                       currentNode,
                       min_height = Number.MAX_VALUE,
                       height,
                       lookup;

                   for (var i = 0; i < mdSectionNodese.length; i++) {
                       currentNode = $(mdSectionNodese[i]);
                       top = currentNode.offset().top;
                       height = currentNode.height();
                       if (top - offsetTop > 0 ) {
                           if (top - offsetTop <= 20) {
                               lastNode = currentNode;
                               offset = 0;
                           }
                           break;
                       }
                       if (top < offsetTop && top + height > offsetTop && height < min_height) {
                           lastNode = currentNode;
                           offset = Math.abs(offsetTop - top) / height;
                           min_height = height;
                       }
                   }

                   if (!lastNode && !currentNode) {
                       //console.log("no found!");
                       $scope.markdownEditor.scrollToLine(0);
                       return;
                   }
                   if (!lastNode) {
                       lastNode = currentNode;
                       offset = 0;
                   }

                   var classNames = lastNode.attr('class').split(/\s+/);
                   for (var i = 0; i < classNames.length; i++) {
                       if (/^_md-/.test(classNames[i].trim())) {
                           lookup = classNames[i].trim();
                       }
                   }

                   var mdTokens = $scope.mdTokens;
                   angular.forEach(mdTokens, function(token) {
                       if (token.random === lookup) {
                           //console.log(lastNode.text());
                           //console.log(JSON.stringify(token));
                           $scope.scrollCount++;
                           // $scope.markdownEditor.scrollToRow(token.startLine + Math.floor(token.span*offset));
                           $scope.markdownEditor.scrollToLine(token.startLine + Math.floor(token.span*offset));
                           return false;
                       }
                   });
               },
               /**
                * synchronizing scroll
                * 当用户滑动editor时，触发事件
                */
               mdScroll: function(){
                   //如果当前鼠标不在Editor上的话，不执行后面的内容
                   //因为如果不禁止的话，会导致editor和preview连动N下最后达到一个静止的状态...
                   if (!$scope.mouse_on_editor) {
                       return;
                   }
                   //1. find the target in current row
                   var tokens = $scope.mdTokens,
                       row = $scope.markdownEditor && $scope.markdownEditor.getFirstVisibleRow(),
                       target,
                       near,
                       diff =  Number.MAX_VALUE,
                       end_diff = Number.MAX_VALUE,
                       offset = 0;

                   if (row === undefined || !tokens || !tokens.length) {
                       return;
                   }

                   //row = row === 0 ? 0 : row + 2;
                   for(var i = 0, len = tokens.length; i < len; i++) {
                       var token = tokens[i];
                       if (token.type === 'space') continue;
                       if (token.type === 'html') continue;

                       if (token.startLine <= row && token.endLine >= row) {
                           if (token.endLine - token.startLine < diff && token.random) {
                               diff = token.span;
                               target = token;
                           }
                       }

                       if (token.endLine <= row && row - token.endLine < end_diff) {
                           near = token;
                       }
                   }

                   //compute offset
                   if (target) {
                       offset = (row - target.startLine) / diff * 100 + "%";
                   } else if (near) {
                       target = near;
                       offset = "100%";
                   } else {
                       $scope.setTargetPlace(0, 0);
                       return;
                   }

                   // offset may be computed as NaN if diff === 0
                   if (target.actual_span === 0) {
                       offset = $scope.markdownEditor.getFirstVisibleRowOffsetPercent();
                       offset = parseInt(offset * 100) + "%";
                       console.log("NaN:" + offset)
                   }
                   $scope.setTargetPlace("." + target.random, offset);
               },
               alignCursorWithPreview: function() {
                   var editor = $scope.markdownEditor,
                       cursor_line = editor.getCursorPosition().row,
                       tokens = $scope.mdTokens,
                       session = editor.getSession(),
                       num_of_line = session.getLength();

                   for (var i = cursor_line + 1, len = num_of_line - cursor_line; i < len; i++) {
                       if (!/^\s*$/.test(session.getLine(i))) {
                           return;
                       }
                   }

                   // a hacky way to make it scroll to bottom.
                   $scope.setTargetPlace(1000000);
               }
           });

           // performance detector
           var last_point = new Date();
           $scope.$watch(function(){
               var new_point = new Date();
               console.log('digest time:' + (new_point - last_point) / 1000 + "s");
               last_point = new_point;
           });


           ["markdownEditorChange", "titleChange"].forEach(function(eventName){
               $scope.$on(eventName, function(event, dirty){
                   if ($scope.selectedNote) {
                       $scope.selectedNote.dirty = dirty;
                   }
               });
           });

       }])
       .config(["$httpProvider", function($httpProvider) {
           $httpProvider.interceptors.push(['$injector', '$q', function($injector, $q) {
               var isAjaxLogining = false;
               return {
                   'responseError': function (response) {
                       if (isAjaxLogining) return $q.reject(response);
                       // 401: Unauthorized, 表示用户需要登录
                       var $dialog = $injector.get("$dialog");
                       var $http = $injector.get("$http");
                       var urlBase = $injector.get("urlBase");
                       var host = $injector.get("host");
                       if (response.status === 401) {
                           $dialog.dialog({
                               backdrop: true,
                               keyboard: false,
                               backdropClick: false,
                               dialogClass: "modal auto-modal",
                               templateUrl: urlBase + "public/template/login-modal.html",
                               controller: ['$scope', 'dialog', function ($scope, dialog) {
                                   isAjaxLogining = true;
                                   angular.extend($scope, {
                                       login: function(email, password) {
                                           $http({
                                               method: "POST",
                                               url: host + "rest/login",
                                               data: $.param({
                                                   email: email,
                                                   password: password
                                               }),
                                               headers: {'Content-Type': 'application/x-www-form-urlencoded'}
                                           }).success(function(response){
                                                   console.log(response);
                                                   isAjaxLogining = false;
                                                   dialog.close();
                                               }).error(function(response){
                                                   console.log(response);
                                                   $scope.error = true;
                                               });
                                       }
                                   })
                               }]
                           }).open();
                       }
                       console.log(response);
                       return $q.reject(response);
                   }
               };
           }]);
       }])
       .value("prefix", "gn")
       .value("host", "http://sailnote.sinaapp.com/")
       .run(function(){
           //dirty jquery
           $(function(){
               //在Pure Preview时，当鼠标移上去时，让代码区尽可能大
               var ndPurePreview = $("#pure-preview");
               ndPurePreview.on("mouseenter mouseleave", "pre code", function(e){
                   var ndCode = $(this),
                       ndPre = ndCode.parent();
                   if (e.type === "mouseenter") {
                       var scrollWidth = ndCode[0].scrollWidth;
                       ndPre.animate({
                           width:  (scrollWidth + 10) + "px"
                       }, 200);
                   } else {
                       ndPre.css('width', "auto");
                   }
               });
           });
       });
}());